package chances.system.operator.web;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Validation;
import javax.validation.ValidatorFactory;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.ObjectMapper;

import chances.system.log.entity.ActionLog;
import chances.system.operator.entity.Menu;
import chances.system.operator.entity.Oplog;
import chances.system.operator.entity.Permission;
import chances.system.operator.entity.Role;
import chances.system.operator.repo.MenuRepository;
import chances.system.operator.repo.PermissionRepository;
import chances.system.operator.repo.RoleRepository;
import chances.webui.model.Tree;
import chances.webui.model.TreeNode;


@RestController
public class PermissionController {

	ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
	 
	@Autowired
	RoleRepository roleRepository;
	
	@Autowired
	MenuRepository menuRepository;
	
	@Autowired
	PermissionRepository permissionRepository;
	
	ObjectMapper objectMapper = new ObjectMapper();
	
	@ActionLog(operateType=Oplog.OP_EDIT, objName="role", desc="修改角色'{name}'权限")
	@RequestMapping(path = "/sys/permission/save", method = RequestMethod.POST)
	public Role savePermission(HttpServletRequest request, @RequestBody PermissionModel model) {
		List<Permission> permissions = 
				permissionRepository.findByObjTypeAndObjIdAndResType(
				model.getObjType(), model.getObjId(), model.getResType());
		
		List<Long> resIds = model.getResIds();
		resIds = filterResId(resIds);
		List<Long> resIdsExec = new ArrayList<Long>();
		resIdsExec.addAll(resIds);
		if(!permissions.isEmpty()){
			for (Permission permission : permissions) {
				if(resIdsExec.contains(permission.getResId())){
					resIds.remove(permission.getResId());
				}else{
					permissionRepository.delete(permission);
				}
			}			
		}

		for (Long resId : resIds) {
			Permission permission = new Permission();
			BeanUtils.copyProperties(model.getPermission(), permission);
			permission.setResId(resId);
			permissionRepository.save(permission);
		}
		
		Role role = this.roleRepository.findOne(model.getObjId());
		request.setAttribute("role", role);
		return role;
	}
	
	/*过滤出最顶级*/
	public List<Long> filterResId(List<Long> resIds){ 
		List<Menu> menus = menuRepository.findByMenuIdIn(resIds);
		Map<Long, String> menuLoacal = new HashMap<Long, String>();
		Map<Long, String> menuLoacalExec = new HashMap<Long, String>();
		for (Menu menu : menus) {
			menuLoacal.put(menu.getMenuId(), menu.getLocation());
			menuLoacalExec.put(menu.getMenuId(), menu.getLocation());
		}
		for (Long menuId1 : menuLoacalExec.keySet()) {
			for (Long menuId2 : menuLoacalExec.keySet()) {
				if (!menuLoacalExec.get(menuId2).equals(menuLoacalExec.get(menuId1)) &&
						menuLoacalExec.get(menuId2).startsWith(menuLoacalExec.get(menuId1))) {
					if(menuLoacal.containsKey(menuId2))
						menuLoacal.remove(menuId2);
				}
			}
		}
		return new ArrayList<Long>(menuLoacal.keySet());
	}
	
	@RequestMapping(path = "/sys/permission/tree/{roleId}", method = RequestMethod.GET)
	public List<Map<String, Object>> getPermissionTree(
			HttpServletRequest httpServletRequest, @PathVariable("roleId") Long roleId) {
		List<Menu> menus = menuRepository.findAvaliableMenu();
		List<TreeNode<Menu>> nodes = menus.stream().map(s -> {
			return createMenuNode(s);
		}).collect(Collectors.toList());
		Tree<Menu> menuTree = new Tree<Menu>(nodes);

		List<Long> ids = new ArrayList<Long>();
		ids.add(roleId);
		List<Permission> perms = this.permissionRepository.findByResTypeAndObjTypeAndObjIdIn("menu", "role", ids);
		Set<Long> menuIds = perms.stream().map(Permission::getResId).collect(Collectors.toSet());
		menus.removeIf(s->{return !menuIds.contains(s.getMenuId());});
		List<Long> nodeIds = menus.stream().map(Menu::getMenuId).collect(Collectors.toList());
		
		List<Map<String, Object>> map = createNodeListMap(menuTree.getRootNodes(), nodeIds);
		return map;
	}

	public TreeNode<Menu> createMenuNode(Menu item) {
		TreeNode<Menu> node = new TreeNode<Menu>();
		node.setEntry(item);
		node.setTitle(item.getTitle());
		node.setPath(item.getLocation());
		node.setId(item.getMenuId().toString());
		node.setLink(item.getHref());
		node.setParentId(item.getParentId().toString());
		return node;
	}
	
	public List<Map<String, Object>> createNodeListMap(List<TreeNode<Menu>> childrens
			, List<Long> nodeIds){
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		if (!childrens.isEmpty()) {
			for (TreeNode<Menu> children : childrens) {
				list.add(createNodeMap(children, nodeIds));
			}
		}
		return list;
	}

	public Map<String, Object> createNodeMap(TreeNode<Menu> node
			, List<Long> nodeIds){
		HashMap<String, Object> map = new HashMap<String, Object>();
		HashMap<String, Object> state = new HashMap<String, Object>();
		
		map.put("id", node.getId());
		map.put("text", node.getTitle());
		if(nodeIds.contains(Long.valueOf(node.getId()))){
			state.put("selected", true);
			map.put("state", state);
		}
		map.put("children", createNodeListMap(node.getChildren(), nodeIds));
		return map;
	}	
}